package tt.dz.biz.service.account;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.CollectionUtils;
import tt.dz.biz.dao.account.AccountingDAO;
import tt.dz.biz.exception.BusinessException;
import tt.dz.biz.service.common.CommonService;
import tt.dz.common.AppContxtUtil;
import tt.dz.common.DzConstants;
import tt.dz.common.DzConstants.PayType;
import tt.dz.common.DzConstants.accountingState;
import tt.dz.common.DzConstants.balanceFlag;
import tt.dz.common.DzConstants.payState;
import tt.dz.common.LogUtil;
import tt.dz.vo.AccountDetailVO;
import tt.dz.vo.MerchAccountDividendVO;
import tt.dz.vo.MerchantSubjectAccVO;
import tt.dz.vo.SubAccountingRuleVO;
import tt.dz.vo.SubjectVO;
import tt.dz.vo.TranInfoVO;
import tt.dz.vo.TranSubVO;

public abstract class AccountDividendPOJO
{
  protected CommonService commonService;
  protected AccountingDAO accountingDAO;
  protected TranInfoVO tranInfoVO;
  protected Date accountingDate;
  protected Date platTime;
  protected List<AccountDetailVO> personalAccountDetailList = new ArrayList(2);
  protected List<MerchAccountDividendVO> merchAccountDividendList = new ArrayList(6);
  protected List<MerchantSubjectAccVO> merchantSubjectList = new ArrayList(6);
  protected boolean originalPayerIsPersonal;
  protected boolean realPayerIsPersonal;
  protected boolean isRealTime;
  protected String bankSubjectCode;
  protected String platMerchantCode;
  protected List<TranSubVO> tranSubVOList;
  protected Map<String, TranInfoVO> totalAmount = new HashMap();
  protected Map<String, TranInfoVO> needRealTimeTotalAmount = new HashMap();
  protected List<TranSubVO> needRealTimeTranSub = new ArrayList();
  protected List<TranSubVO> merchantTranSubList = new ArrayList();
  protected AccountDividendSupport accDivSupport = new AccountDividendSupport();
  
  public Date getAccountingDate()
  {
    return this.accountingDate;
  }
  
  public void setAccountingDate(Date accountingDate)
    throws Exception
  {
    this.accountingDate = accountingDate;
  }
  
  public TranInfoVO getTranInfoVO()
  {
    return this.tranInfoVO;
  }
  
  public void setTranInfoVO(TranInfoVO tranInfoVO)
  {
    this.tranInfoVO = tranInfoVO;
  }
  
  public AccountDividendPOJO(TranInfoVO tranInfoVO)
    throws Exception
  {
    this.tranInfoVO = tranInfoVO;
    init();
  }
  
  public AccountDividendPOJO() {}
  
  public Integer queryIndividualDetailSeq()
  {
    Long seq = this.accountingDAO.querySequence("individual_account_detail_seq");
    return Integer.valueOf(seq.intValue());
  }
  
  public void updateTranInfoEndAccounting()
    throws Exception
  {
    this.tranInfoVO.setEndAccountTime(this.commonService.getDBCurrentTime());
    this.tranInfoVO.setAccountState(DzConstants.accountingState.ACCOUNTED.value());
    int rs = this.accountingDAO.updateTranInfoEndAccounting(this.tranInfoVO);
    if (rs == 0) {
      throw new BusinessException("更新交易记录记账状态为已记账时失败，参数为：" + this.tranInfoVO);
    }
  }
  
  public void saveEndAccounting()
    throws Exception
  {
    try
    {
      updateTranInfoEndAccounting();
      saveAccountDividend();
      updateMerchantSubjectBalance();
    }
    catch (Exception e)
    {
      LogUtil.error("保存账户分录失败和个人账户明细失败，运营商账户分录为：" + this.merchAccountDividendList + ",个人账户明细参数为：" + this.personalAccountDetailList);
      LogUtil.error("需要更新账户余额的运营商账户列表为：" + this.merchantSubjectList);
      LogUtil.error("保存账户分录失败和个人账户明细失败，交易记录为：" + this.tranInfoVO, e);
      throw e;
    }
  }
  
  public abstract void saveAccountDividend()
    throws Exception;
  
  private AccountDividendPOJO init()
    throws Exception
  {
    try
    {
      if (null == this.tranInfoVO) {
        throw new Exception("交易记录为空，不能记账户分录");
      }
      this.tranSubVOList = this.tranInfoVO.getTranSubVOList();
      this.accountingDAO = ((AccountingDAO)AppContxtUtil.getBean("accountingRuleDAO"));
      this.commonService = ((CommonService)AppContxtUtil.getBean("commonService"));
      setAccountingDate(this.commonService.getAccountingDate());
      this.platTime = this.commonService.getDBCurrentTime();
      this.isRealTime = DzConstants.payState.PAY_SUCCESS.value().equals(this.tranInfoVO.getPayStateCode());
      if ((this.isRealTime) && ((DzConstants.PayType.THIRD_REALTIME_PAY.value().equals(this.tranInfoVO.getPayTypeCode())) || 
        (DzConstants.PayType.CASH_PAY.value().equals(this.tranInfoVO.getPayTypeCode()))))
      {
        SubjectVO subjectVO = this.accountingDAO.queryBankAccount(this.tranInfoVO.getChannelCode());
        this.bankSubjectCode = subjectVO.getSubjectCode();
      }
    }
    catch (Exception e)
    {
      LogUtil.error("初始化交易记录公用部分失败", e);
      throw e;
    }
    return this;
  }
  
  protected MerchantSubjectAccVO setMerchantSubject(MerchAccountDividendVO detail, Integer balanceFlag)
  {
    MerchantSubjectAccVO mertchSubject = new MerchantSubjectAccVO();
    mertchSubject.setMerchantCode(detail.getMerchantCode());
    mertchSubject.setSubSubjectCode(detail.getSubSubjectCode());
    if (DzConstants.balanceFlag.REDUCTION.value().equals(balanceFlag)) {
      mertchSubject.setAcctBal(BigDecimal.valueOf(0L).subtract(detail.getAmount()));
    } else {
      mertchSubject.setAcctBal(detail.getAmount());
    }
    return mertchSubject;
  }
  
  protected void setRelatedAccountDetail(TranSubVO tmp, Long ruleSeq)
    throws Exception
  {
    MerchAccountDividendVO subDetail = new MerchAccountDividendVO();
    SubAccountingRuleVO subRule = this.accountingDAO.querySubAccountingRuleByRuleSeq(ruleSeq);
    subDetail.setAccountingDate(this.accountingDate);
    subDetail.setMerchantCode1(tmp.getReceiver());
    subDetail.setMerchantCode(this.platMerchantCode);
    subDetail.setAmount(tmp.getPaymentAmount());
    subDetail.setSubjectCode(subRule.getSubjectCode());
    subDetail.setSubSubjectCode(subRule.getSubSubjectCode());
    subDetail.setLoanFlag(subRule.getLoanFlag());
    subDetail.setTradeNo(this.tranInfoVO.getTradeNo());
    this.merchAccountDividendList.add(subDetail);
    this.merchantSubjectList.add(setMerchantSubject(subDetail, subRule.getBalanceFlag()));
  }
  
  private void updateMerchantSubjectBalance()
    throws Exception
  {
    if (!CollectionUtils.isEmpty(this.merchantSubjectList))
    {
      int[] rs = this.accountingDAO.updateMerchantSubjectBalance(this.merchantSubjectList);
      judgeResult(rs, "更新运营商账户余额失败，参数为：" + this.merchantSubjectList);
    }
  }
  
  protected void judgeResult(int[] rs, String errorMsg)
    throws BusinessException
  {
    if (null == rs)
    {
      LogUtil.error(errorMsg);
      throw new BusinessException(errorMsg);
    }
    for (int i : rs) {
      if (i == 0)
      {
        LogUtil.error(errorMsg);
        throw new BusinessException(errorMsg);
      }
    }
  }
  
  protected List<MerchAccountDividendVO> mergeMerchAccountDividend(List<MerchAccountDividendVO> paramList)
  {
    return this.accDivSupport.mergeMerchAccountDividend(paramList);
  }
}
